import Constants from '@/components/hhd/design/FormEngine/Constants';
import {postAction} from '@api/manage';
import {openComponent} from '@/utils/FormDesignUtils';
import FormCheckMessageModal from '@comp/hhd/design/FormEngine/FormCheckMessageModal.vue';

export default class FormEngineContext {
  vue;
  formDefinition;
  viewId;
  actionId;
  formModel;
  emit;
  setProperty;

  //下面是运行时产生的数据
  view;
  action;
  templateConfigs;
  h;

  constructor(vue, initModel = true) {
    this.vue = vue;
    this.formDefinition = vue.$props.formDefinition;
    this.viewId = vue.$props.view;
    this.actionId = vue.$props.action;
    this.formModel = vue.$props.formModel;
    this.emit = vue.$emit;
    this.setProperty = vue.$set;
    this.h = vue.$createElement;

    if (initModel) this.initIfNecessary();
  }

  initIfNecessary() {
    this.view = this.formDefinition.views.find(v => v.id === this.viewId);
    this.action = this.formDefinition.actions.find(a => a.id === this.actionId);
    this.templateConfigs = this.view && this.view.templateConfigs || undefined;
    this.buildModelIfNecessary();
  }

  buildModelIfNecessary() {
    if (!this.formModel) {
      this.changeFormModel({});
    } else {
      this.buildMainFields();
      this.buildSubFormFields();
      this.buildMainAuthFields();
      this.buildSubAuthFields();
      this.buildSubFormAuthFields();
    }
  }

  changeFormModel(formModel) {
    this.vue.$emit('change', formModel);
  }

  buildMainAuthFields() {
    this.doBuildAuthFields(this.formModel, this.formDefinition);
    this.doBuildRequiredFields(this.formModel, this.formDefinition);
  }

  doBuildRequiredFields(model, formDefinition) {
    let required = model[Constants.requiredFieldName] || {};
    let fields = formDefinition && formDefinition.fields || [];
    fields.forEach(f => {
      let fieldActions = this.action && this.action.fieldActions || [];
      let fieldRequired = false;
      fieldActions.forEach(fa => {
        if (fa.fieldId === f.id) fieldRequired = fa.required;
      });
      this.setProperty(required, f.fieldName, this.resolveFieldRequired(required[f.fieldName], fieldRequired, false));
    });
    this.setProperty(model, Constants.requiredFieldName, required);
  }

  resolveFieldRequired(originRequired, defaultRequired, systemDefaultRequired) {
    if (originRequired !== null && originRequired !== undefined) return originRequired;
    if (defaultRequired !== null && defaultRequired !== undefined) return defaultRequired;
    return systemDefaultRequired;
  }

  buildSubFormAuthFields() {
    let subForms = this.formDefinition.subForms || [];
    let subFormAuth = this.formModel[Constants.subFormAuthFieldName] || {};
    this.setProperty(this.formModel, Constants.subFormAuthFieldName, subFormAuth);
    let subFormActions = this.action && this.action.subFormActions || [];
    subForms.forEach(subForm => {
      let authObj = subFormAuth[subForm.id] || {};
      let subFormAction = subFormActions.find(s => s.subFormId === subForm.id) || {};
      !authObj.hasOwnProperty('addRow') && this.setProperty(authObj, 'addRow', !!subFormAction.addRow);
      !authObj.hasOwnProperty('copyRow') && this.setProperty(authObj, 'copyRow', !!subFormAction.copyRow);
      !authObj.hasOwnProperty('removeRow') && this.setProperty(authObj, 'removeRow', !!subFormAction.removeRow);
      !authObj.hasOwnProperty('clearRow') && this.setProperty(authObj, 'clearRow', !!subFormAction.clearRow);
      !authObj.hasOwnProperty('moveUp') && this.setProperty(authObj, 'moveUp', !!subFormAction.moveUp);
      !authObj.hasOwnProperty('moveDown') && this.setProperty(authObj, 'moveDown', !!subFormAction.moveDown);
      this.setProperty(subFormAuth, subForm.id, authObj);
    });
  }

  buildSubAuthFields() {
    let subForms = this.formDefinition.subForms || [];
    subForms.forEach(subForm => {
      let subFormModels = this.formModel[subForm.id] || [];
      subFormModels.forEach(subFormModel => {
        this.doBuildAuthFields(subFormModel, subForm);
        this.doBuildRequiredFields(subFormModel, subForm);
      });
    });
  }

  doBuildAuthFields(model, formDefinition) {
    let auth = model[Constants.authFieldName] || {};
    let fields = formDefinition && formDefinition.fields || [];
    fields.forEach(f => {
      let fieldActions = this.action && this.action.fieldActions || [];
      let fieldAuth = 'edit';
      fieldActions.forEach(fa => {
        if (fa.fieldId === f.id) {
          fieldAuth = fa.auth;
        }
      });
      this.setProperty(auth, f.fieldName, auth[f.fieldName] || fieldAuth || 'edit');
    });
    this.setProperty(model, Constants.authFieldName, auth);
  }

  buildMainFields() {
    this.buildFields(this.formDefinition, this.formModel);
  }

  buildSubFormFields() {
    let subForms = this.formDefinition.subForms || [], model = this.formModel;
    subForms.forEach(subForm => {
      let subFormDataSource = model[subForm.id] || [];
      this.setProperty(model, subForm.id, subFormDataSource);
      subFormDataSource.forEach(item => {
        this.buildFields(subForm, item);
      });
    });
  }

  buildFields({fields}, model) {
    fields = fields || [];
    fields.forEach(f => {
      this.setProperty(model, f.fieldName, model[f.fieldName]);
      f.fieldTitleName && this.setProperty(model, f.fieldTitleName, model[f.fieldTitleName]);
    });
  }

  check() {
    return !!this.view && !!this.view && !!this.view.templateConfigs;
  }

  resetAction() {
    let temp = {...this.formModel};
    temp._auth = undefined;

    let subForms = this.formDefinition.subForms || [], model = temp;
    subForms.forEach(subForm => {
      let subFormDataSource = model[subForm.id] || [];
      this.setProperty(model, subForm.id, subFormDataSource);
      subFormDataSource.forEach(item => {
        item[Constants.authFieldName] = undefined;
        item[Constants.requiredFieldName] = undefined;
        this.buildFields(subForm, item);
      });
    });
    this.changeFormModel(temp);
  }

  updateSubFormData() {
    this.formFieldUpdate();
  }

  formFieldUpdate(fieldConfig, rowId) {
    if (!window.updateCount) window.updateCount = 1;
    let tempUpdateCount = ++window.updateCount;
    postAction('/form/formFieldUpdate', {
      rowId,
      actionId: this.actionId,
      fieldId: fieldConfig && fieldConfig.id || undefined,
      formModel: this.formModel,
      formDefinitionId: this.formDefinition.id
    }).then(({result}) => {
      (tempUpdateCount === window.updateCount) && result && (this.changeFormModel(result) || this.updateAutoRelation(result, tempUpdateCount));
    }).catch(console.error);
  }

  updateAutoRelation(formModel, tempUpdateCount) {
    let actionId = this.actionId;
    let viewId = this.viewId;
    postAction('/form/autoRelation', {
      formModel,
      actionId,
      viewId,
      formDefinitionId: this.formDefinition.id
    }).then(({result}) => {
      (tempUpdateCount === window.updateCount) && result && this.changeFormModel(result);
    }).catch(console.error);
  }

  autoRelation() {
    return new Promise((success, err) => {
      let tempUpdateCount = ++window.updateCount;
      postAction('/form/autoRelation', {
        formModel: this.formModel,
        actionId: this.actionId,
        viewId: this.viewId,
        formDefinitionId: this.formDefinition.id
      }).then(({result}) => {
        if (tempUpdateCount === window.updateCount && result) {
          this.changeFormModel(result);
          success && success();
        }
      }).catch(console.error);
    });
  }

  checkFormData() {
    return new Promise((success, err) => {
      let promises = [
        () => this.checkRequired(),
        () => this.chechRules()
      ];

      function deep(promises, index = 0) {
        promises.length === index + 1 ? promises[index]().then(success).catch(err || console.error) :
          promises[index]().then(() => deep(promises, index + 1)).catch(err || console.error);
      }

      deep(promises);
    });
  }

  chechRules() {
    return new Promise((success, err) => {
      let data = {formModel: this.formModel, actionId: this.actionId, formDefinitionId: this.formDefinition.id};
      postAction('/form/checkRules', data).then(({result}) => {
        if (result.messages && result.messages.length) {
          this.showMessages(result.messages, () => success(this.formModel));
          return;
        }
        success();
      });
    });
  }

  showMessages(messages, callback) {
    openComponent(FormCheckMessageModal, {props: {messages, callback}});
  }

  checkRequired() {
    return new Promise((success, err) => {
      let fields = this.formDefinition.fields, required = this.formModel[Constants.requiredFieldName] || {};
      for (let i = 0; i < fields.length; i++) {
        if (required[fields[i].fieldName] === true
          && !this.formModel[fields[i].fieldName]
          && this.formModel[fields[i].fieldName] !== '0') {
          this.vue.$message.warn('请将必填项填写完整');
          return;
        }
      }
      let subForms = this.formDefinition.subForms || [];
      for (let i = 0; i < subForms.length; i++) {
        let subForm = subForms[i];
        fields = subForm.fields || [];
        let subFormDataSource = this.formModel[subForm.id] || [];
        for (let j = 0; j < subFormDataSource.length; j++) {
          for (let k = 0; k < fields.length; k++) {
            let field = fields[k];
            let subFormData = subFormDataSource[j];
            required = subFormData[Constants.requiredFieldName] || {};
            if (required[field.fieldName] === true && !subFormData[field.fieldName]) {
              this.vue.$message.warn('请将必填项填写完整');
              return;
            }
          }
        }
      }
      success();
    });
  }

  initFormData(callback) {
    postAction('/form/initFormData', {
      formDefinitionId: this.formDefinition.id,
      actionId: this.actionId,
    }).then(({result}) => {
      this.changeFormModel(result || {});
      callback && callback();
    });
  }
}